package com.pcbly.web.components.utils.theme;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Pattern;

import org.apache.commons.lang.StringUtils;

@SuppressWarnings("unchecked")
public class ResourceBundleRule implements Serializable {

	/**
	 * 
	 */
	private static final long serialVersionUID = 7791630730472493241L;
	private SearchTarget searchTarget;
	private SearchOperator operator;
	private String pattern;
	private String replaceValue;

	private List excludeRules;

	public static class ExcludeRule implements Serializable {

		/**
		 * 
		 */
		private static final long serialVersionUID = -7916652710892494693L;

		public SearchTarget getSearchTarget() {
			return searchTarget;
		}

		public SearchOperator getOperator() {
			return operator;
		}

		public String getPattern() {
			return pattern;
		}

		public void setSearchTarget(SearchTarget searchTarget) {
			this.searchTarget = searchTarget;
		}

		public void setOperator(SearchOperator operator) {
			this.operator = operator;
		}

		public void setPattern(String pattern) {
			this.pattern = pattern;
		}

		public boolean criteriaEquals(ExcludeRule rule) {
			if (!rule.getSearchTarget().equals(searchTarget))
				return false;
			if (!rule.getOperator().equals(operator))
				return false;
			return rule.getPattern().equals(pattern);
		}

		private SearchTarget searchTarget;
		private SearchOperator operator;
		private String pattern;

		public ExcludeRule() {
		}

		public ExcludeRule(SearchTarget target, SearchOperator operator,
				String pattern) {
			searchTarget = target;
			this.operator = operator;
			this.pattern = pattern;
		}
	}

	public static final class SearchOperator {

		public static final SearchOperator[] values() {
			return (SearchOperator[]) $VALUES.clone();
		}

		public static SearchOperator valueOf(String name) {
			return null;
		}

		private final String name;
		private final int ordinal;
		public static final SearchOperator EQUALS;
		public static final SearchOperator CONTAINS;
		public static final SearchOperator STARTS_WITH;
		public static final SearchOperator ENDS_WITH;
		public static final SearchOperator REG_EX;
		private static final SearchOperator $VALUES[];

		static {
			EQUALS = new SearchOperator("EQUALS", 0);
			CONTAINS = new SearchOperator("CONTAINS", 1);
			STARTS_WITH = new SearchOperator("STARTS_WITH", 2);
			ENDS_WITH = new SearchOperator("ENDS_WITH", 3);
			REG_EX = new SearchOperator("REG_EX", 4);
			$VALUES = (new SearchOperator[] { EQUALS, CONTAINS, STARTS_WITH,
					ENDS_WITH, REG_EX });
		}

		private SearchOperator(String name, int ordinal) {
			this.name = name;
			this.ordinal = ordinal;
		}

		public final int ordinal() {
			return ordinal;
		}

		public final String name() {
			return name;
		}

		public String toString() {
			return name;
		}
	}

	public static final class SearchTarget {

		public static final SearchTarget[] values() {
			return (SearchTarget[]) $VALUES.clone();
		}

		public static SearchTarget valueOf(String name) {
			return null;
		}

		private final String name;
		private final int ordinal;
		public static final SearchTarget KEY;
		public static final SearchTarget VALUE;
		private static final SearchTarget $VALUES[];

		static {
			KEY = new SearchTarget("KEY", 0);
			VALUE = new SearchTarget("VALUE", 1);
			$VALUES = (new SearchTarget[] { KEY, VALUE });
		}

		private SearchTarget(String name, int ordinal) {
			this.name = name;
			this.ordinal = ordinal;
		}

		public final int ordinal() {
			return ordinal;
		}

		public final String name() {
			return name;
		}

		public String toString() {
			return name;
		}
	}

	public ResourceBundleRule() {
	}

	private Object readResolve() {
		if (excludeRules == null)
			excludeRules = new ArrayList();
		return this;
	}

	public ResourceBundleRule(SearchTarget target, SearchOperator operator,
			String pattern, String replaceValue, List excludeRules) {
		searchTarget = target;
		this.operator = operator;
		this.pattern = pattern;
		this.replaceValue = replaceValue;
		this.excludeRules = ((List) (excludeRules != null ? excludeRules
				: ((List) (new ArrayList()))));
	}

	public List getExcludeRules() {
		return excludeRules;
	}

	public SearchTarget getSearchTarget() {
		return searchTarget;
	}

	public void setSearchTarget(SearchTarget searchTarget) {
		this.searchTarget = searchTarget;
	}

	public void setOperator(SearchOperator operator) {
		this.operator = operator;
	}

	public void setPattern(String pattern) {
		this.pattern = pattern;
	}

	public void setReplaceValue(String replaceValue) {
		this.replaceValue = replaceValue;
	}

	public void setExcludeRules(List excludeRules) {
		this.excludeRules = excludeRules;
	}

	public SearchOperator getOperator() {
		return operator;
	}

	public String getPattern() {
		return pattern;
	}

	public String getReplaceValue() {
		return replaceValue;
	}

	public boolean criteriaEquals(ResourceBundleRule rule) {
		if (!rule.getSearchTarget().equals(searchTarget))
			return false;
		if (!rule.getOperator().equals(operator))
			return false;
		if (!rule.getPattern().equals(pattern))
			return false;
		if (rule.getExcludeRules().size() != excludeRules.size())
			return false;
		for (Iterator i$ = rule.getExcludeRules().iterator(); i$.hasNext();) {
			ExcludeRule exclude = (ExcludeRule) i$.next();
			boolean match = false;
			Iterator it = excludeRules.iterator();
			do {
				if (!it.hasNext())
					break;
				ExcludeRule thisExclude = (ExcludeRule) it.next();
				if (thisExclude.criteriaEquals(exclude))
					match = true;
			} while (true);
			if (!match)
				return false;
		}

		return true;
	}

	protected boolean checkMatch(String value, SearchOperator operator,
			String pattern) {
		final int searchOperator[] = new int[] { 1, 2, 3, 4, 5 };
		switch (searchOperator[operator.ordinal()]) {
		case 1: // '\001'
			return value.equals(pattern);

		case 2: // '\002'
			return value.contains(pattern);

		case 3: // '\003'
			return value.startsWith(pattern);

		case 4: // '\004'
			return value.endsWith(pattern);

		case 5: // '\005'
			return Pattern.compile(pattern).matcher(value).find();
		}
		return false;
	}

	protected boolean checkExcludeMatch(String key, String value) {
		for (Iterator i$ = excludeRules.iterator(); i$.hasNext();) {
			ExcludeRule exclude = (ExcludeRule) i$.next();
			if (checkMatch(
					exclude.getSearchTarget() != SearchTarget.KEY ? value : key,
					exclude.getOperator(), exclude.getPattern()))
				return true;
		}

		return false;
	}

	public String applyRule(String key, String value) {
		if (checkIgnoreSpecialKey(key))
			return null;
		if (checkExcludeMatch(key, value))
			return null;
		if (checkMatch(getSearchTarget() != SearchTarget.KEY ? value : key,
				getOperator(), getPattern()))
			return getSearchTarget() != SearchTarget.KEY ? value.replaceAll(
					getPattern(), replaceValue) : replaceValue;
		else
			return null;
	}

	protected boolean checkIgnoreSpecialKey(String key) {
		return key.indexOf(".ignore_phrase_subst") > -1;
	}

	private static String capitalizeFirstLetter(String text) {
		if (text.length() == 0)
			return text;
		else
			return (new StringBuilder()).append(
					text.substring(0, 1).toUpperCase()).append(
					text.toLowerCase().subSequence(1, text.length()))
					.toString();
	}

	public static List createRulesForContainsWord(String word,
			String replaceValue) {
		List rules = new ArrayList();
		replaceValue = StringUtils.replace(replaceValue, "'", "''");
		rules.add(new ResourceBundleRule(SearchTarget.VALUE,
				SearchOperator.REG_EX, (new StringBuilder()).append("\\b")
						.append(word.toLowerCase()).append("\\b").toString(),
				replaceValue.toLowerCase(), null));
		rules
				.add(new ResourceBundleRule(SearchTarget.VALUE,
						SearchOperator.REG_EX, (new StringBuilder()).append(
								"\\b").append(capitalizeFirstLetter(word))
								.append("\\b").toString(),
						capitalizeFirstLetter(replaceValue), null));
		return rules;
	}

}
